
/**
 * CompareVersions 版本号比较助手类
 * https://github.com/omichelsen/compare-versions
 */
 class CompareVersions {
	// 总开关
	static enable = true;
	semver =
		/^v?(?:\d+)(\.(?:[x*]|\d+)(\.(?:[x*]|\d+)(\.(?:[x*]|\d+))?(?:-[\da-z\-]+(?:\.[\da-z\-]+)*)?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i;

	// 构造方法
	constructor() {}
	indexOrEnd(str, q) {
		return str.indexOf(q) === -1 ? str.length : str.indexOf(q);
	}

	split(v) {
		var c = v.replace(/^v/, '').replace(/\+.*$/, '');
		var patchIndex = this.indexOrEnd(c, '-');
		var arr = c.substring(0, patchIndex).split('.');
		arr.push(c.substring(patchIndex + 1));
		return arr;
	}

	tryParse(v) {
		return isNaN(Number(v)) ? v : Number(v);
	}

	validate2 = (version) => {
		if (typeof version !== 'string') {
			throw new TypeError('Invalid argument expected string');
		}
		if (!this.semver.test(version)) {
			throw new Error('Invalid argument not valid semver (\'' + version + '\' received)');
		}
	}

	compareVersions = (v1, v2) => {
		[v1, v2].forEach(this.validate);

		var s1 = this.split(v1);
		var s2 = this.split(v2);

		for (var i = 0; i < Math.max(s1.length - 1, s2.length - 1); i++) {
			var n1 = parseInt(s1[i] || 0, 10);
			var n2 = parseInt(s2[i] || 0, 10);

			if (n1 > n2) return 1;
			if (n2 > n1) return -1;
		}

		var sp1 = s1[s1.length - 1];
		var sp2 = s2[s2.length - 1];

		if (sp1 && sp2) {
			var p1 = sp1.split('.').map(tryParse);
			var p2 = sp2.split('.').map(tryParse);

			for (i = 0; i < Math.max(p1.length, p2.length); i++) {
				if (p1[i] === undefined || typeof p2[i] === 'string' && typeof p1[i] === 'number') return -1;
				if (p2[i] === undefined || typeof p1[i] === 'string' && typeof p2[i] === 'number') return 1;

				if (p1[i] > p2[i]) return 1;
				if (p2[i] > p1[i]) return -1;
			}
		} else if (sp1 || sp2) {
			return sp1 ? -1 : 1;
		}

		return 0;
	};

	allowedOperators = [
		'>',
		'>=',
		'=',
		'<',
		'<='
	];

	operatorResMap = {
		'>': [1],
		'>=': [0, 1],
		'=': [0],
		'<=': [-1, 0],
		'<': [-1]
	};

	validateOperator(op) {
		if (typeof op !== 'string') {
			throw new TypeError('Invalid operator type, expected string but got ' + typeof op);
		}
		if (this.allowedOperators.indexOf(op) === -1) {
			throw new TypeError('Invalid operator, expected one of ' + this.allowedOperators.join('|'));
		}
	}

	validate = (version) => {
		return typeof version === 'string' && this.semver.test(version);
	}

	compare = (v1, v2, operator = '>') => {
		// Validate operator
		this.validateOperator(operator);

		// since result of compareVersions can only be -1 or 0 or 1
		// a simple map can be used to replace switch
		var res = this.compareVersions(v1, v2);
		return this.operatorResMap[operator].indexOf(res) > -1;
	}
	/**
	 * 一键测试
	 */
	test() {
		let a = this.compare('10.1.8', '10.0.4', '>'); // return true
		console.log('a1=true', a);
		a = this.compare('10.0.1', '10.0.1', '='); // return true
		console.log('a2=true', a);
		a = this.compare('10.1.1', '10.2.2', '<'); // return true
		console.log('a3=true', a);
		a = this.compare('10.1.1', '10.2.2', '<='); // return true
		console.log('a4=true', a);
		a = this.compare('10.1.1', '10.2.2', '>='); // return false
		console.log('a5=false', a);
		a = this.validate('1.0.0-rc.1'); // return true
		console.log('a6=true', a);
		a = this.validate('1.0-rc.1'); // return false
		console.log('a7=false', a);
		a = this.validate('foo'); // return false
		console.log('a8=false', a);
	}
	async checkUpdate(options = {}) {
		if (!CompareVersions.enable) {
			console.log('[检测版本更新] 全局关闭');
			return;
		}
		if (typeof(plus) == 'undefined') {
			console.log('[检测版本更新] 不支持 plus 插件，退出检测更新');
			return;
		}
		let _default = {
			isDebug: true,
			url: 'http://www.byaso.com/index.php/api/check_version?os=android', // 服务器版本比较的URL
			data: {}, // 传递的参数
			updateHandler: function(data, isUpdate = false, isForce = false) {
				// 强制更新
				_class.versionInfo.isForce = data.force == '1';
				_class.versionInfo.downloadUrl = data.download_url || '';
				_class.versionInfo.version = data.version;
				_class.versionInfo.content = data.content || '暂无更新内容';
				_class.versionInfo.network = plus.networkinfo.getCurrentType() == 3 ?
					'Wifi网络' :
					'数据流量';
				_class.$refs['dlgVersion'].open();
			}
		}
		options = Object.assign(_default, options);
		// 获取本地应用的版本号
		const widgetInfo = await new Promise(function(reslove, reject) {
			plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {
				reslove(widgetInfo);
			});
		})
		if (options.isDebug) {
			console.log('[检测版本更新] 本地应用信息 widgetInfo=', widgetInfo);
		}
		// 获取远程服务器的版本信息
		let params = {
			version: widgetInfo.version,
			name: widgetInfo.name
		}
		params = Object.assign(params, options.data); // 额外增加参数
		const [error, result] = await uni.request({
			url: options.url,
			data: params
		});
		if (options.isDebug) {
			console.log('[版本更新] 服务器返回 result=', result);
		}
		// 升级信息
		var data = result.data.data;
		data.local_version = widgetInfo.version;
		data.isUpdate = this.compare(data.version, widgetInfo.version);
		if (options.isDebug) {
			console.log('[版本更新] ' + (data.isUpdate ? '[需要更新]' : '[无需更新]') + ' 升级信息 data=', data);
		}
		options.updateHandler(data, data.isUpdate, data.force == '1');
	}
}

export default CompareVersions;
